/*
 * 描述： <描述>
 * 修改人： rain
 * 修改时间： 2016年1月24日
 * 项目： rainhy-cores-webcore
 */
package com.rainhy.webcore.holder;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

import com.rainhy.core.util.AssertUtils;

/**
 * HttpSession Holder
 * 
 * @author rain
 * @version [版本号, 2016年1月24日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Component("rainhy.webcore.HttpSessionHolder")
public class HttpSessionHolder implements InitializingBean, FactoryBean<HttpSessionHolder> {
    
    /** 日志 */
    private static final Logger logger = LoggerFactory.getLogger(HttpSessionHolder.class);
    
    /** 自身唯一引用 */
    private static HttpSessionHolder holder;
    
    /** HttpSession列表 */
    private static Map<String, HttpSession> httpSessionMap;
    
    /** 是否已经初始化 */
    private static boolean sessionInitializ = false;
    
    /** 返回自身唯一引用 */
    public static HttpSessionHolder get() {
        return HttpSessionHolder.holder;
    }
    
    /**
     * 
     * 获取 session<br>
     * 如果 createNew 传入 true ,如果找不到 session, 则新建一个返回
     *
     * @param createNew 如果找不到 session, 是否新建
     * 
     * @return HttpSession [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年1月20日]
     * @author rain
     */
    public static HttpSession getSession(boolean createNew) {
        return WebContextHolder.getRequest().getSession(createNew);
    }
    
    /** 根据 session id 返回对应的 HttpSession */
    public static HttpSession getSession(String sessionId) {
        HttpSessionHolder holder = HttpSessionHolder.get();
        AssertUtils.isTrue(holder.isSessionInitializ(), "请在 web.xml 中注入一个 HttpSessionListener, 用来监听 HttpSession 的创建和注销");
        return holder.getSessionMap().get(sessionId);
    }
    
    /**
     * 
     * 获取 session 属性值
     *
     * @param name 属性名
     * 
     * @return Object [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年1月20日]
     * @author rain
     */
    public static Object getSessionAttribute(String name) {
        HttpSession session = getSession(false);
        if (session == null) {
            return null;
        }
        return session.getAttribute(name);
    }
    
    /**
     * 
     * 获取 session 属性值
     *
     * @param name 属性名
     * @param type 属性值类型
     * 
     * @return T 属性值
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年1月20日]
     * @author rain
     */
    @SuppressWarnings("unchecked")
    public static <T> T getSessionAttribute(String name, Class<T> type) {
        HttpSession session = getSession(false);
        if (session == null) {
            return null;
        }
        return (T) session.getAttribute(name);
    }
    
    /**
     * 
     * 获取 session 属性值集合
     *
     * @param name 属性名
     * @param type 属性值类型
     * 
     * @return List<T> 属性值集合
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年1月20日]
     * @author rain
     */
    @SuppressWarnings("unchecked")
    public static <T> List<T> getSessionAttributeList(String name, Class<T> type) {
        HttpSession session = getSession(false);
        if (session == null) {
            return null;
        }
        return (List<T>) session.getAttribute(name);
    }
    
    /** 返回一个不可修改的 HttpSession 集合 */
    public static Collection<HttpSession> getSessions() {
        HttpSessionHolder holder = HttpSessionHolder.get();
        AssertUtils.isTrue(holder.isSessionInitializ(), "请在 web.xml 中注入一个 HttpSessionListener, 用来监听 HttpSession 的创建和注销");
        return Collections.unmodifiableCollection(holder.getSessionMap().values());
    }
    
    /** 返回 HttpSession 数量 */
    public static int getSessionSize() {
        HttpSessionHolder holder = HttpSessionHolder.get();
        AssertUtils.isTrue(holder.isSessionInitializ(), "请在 web.xml 中注入一个 HttpSessionListener, 用来监听 HttpSession 的创建和注销");
        return holder.getSessionMap().size();
    }
    
    /**
     * 
     * 移除 session 属性值
     *
     * @param name 属性名
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年1月20日]
     * @author rain
     */
    public static void removeSessionAttribute(String name) {
        HttpSession session = getSession(false);
        if (session != null)
            session.removeAttribute(name);
    }
    
    /** 创建 HttpSession */
    public static void sessionCreated(HttpSessionEvent se) {
        AssertUtils.isTrue(sessionInitializ, "请在 web.xml 中注入 RainhySessionListener");
        HttpSession session = se.getSession();
        httpSessionMap.put(session.getId(), session);
    }
    
    /** 注销 HttpSession */
    public static void sessionDestroyed(HttpSessionEvent se) {
        AssertUtils.isTrue(sessionInitializ, "请在 web.xml 中注入 RainhySessionListener");
        HttpSession session = se.getSession();
        httpSessionMap.remove(session.getId());
    }
    
    /**
     * 初始化 HttpSessionListener<br>
     * 在 web.xml 中注入 HttpSessionListener 后才能使用此类功能<br>
     * 
     * <pre>
     *  &lt;listener/&gt;
     *      &lt;listener-class&gt;com.rainhy.webcore.eventlistener.RainhySessionListener&lt;/listener-class&gt;
     *  &lt;/listener&gt;
     * </pre>
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年1月24日]
     * @author rain
     */
    public static void sessionInitializ() {
        sessionInitializ = true;
        httpSessionMap = new ConcurrentHashMap<>();
    }
    
    /**
     * 
     * 设置 session 属性值
     *
     * @param name 属性名
     * @param value 属性值
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年1月20日]
     * @author rain
     */
    public static void setSessionAttribute(String name, Object value) {
        HttpSession session = getSession(true);
        if (session != null)
            if (value != null) {
                session.setAttribute(name, value);
            } else {
                session.removeAttribute(name);
            }
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        HttpSessionHolder.holder = this;
        logger.info("加载[HttpSession Holder]...");
    }
    
    @Override
    public HttpSessionHolder getObject() throws Exception {
        return HttpSessionHolder.get();
    }
    
    @Override
    public Class<?> getObjectType() {
        return HttpSessionHolder.class;
    }
    
    /** 返回一个不可修改的 HttpSession Map */
    public Map<String, HttpSession> getSessionMap() {
        return Collections.unmodifiableMap(httpSessionMap);
    }
    
    /** SessionListener 是否已经初始化 */
    public boolean isSessionInitializ() {
        return sessionInitializ;
    }
    
    @Override
    public boolean isSingleton() {
        return true;
    }
}
